package com.myproject.utils;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 文件操作工具类
 * 
 * <p>封装常用的文件操作方法，基于Java NIO.2 API实现。</p>
 */
public class FileUtils {

    private FileUtils() {
        // 私有构造方法防止实例化
    }

    // ------------------- 文件读写操作 -------------------

    /**
     * 读取文件内容为字符串（UTF-8编码）
     * @param filePath 文件路径
     * @return 文件内容
     * @throws IOException 读取异常
     */
    public static String readFileToString(String filePath) throws IOException {
        return readFileToString(Paths.get(filePath), StandardCharsets.UTF_8);
    }

    /**
     * 读取文件内容为字符串（指定编码）
     * @param filePath 文件路径
     * @param charset 字符编码
     * @return 文件内容
     * @throws IOException 读取异常
     */
    public static String readFileToString(String filePath, Charset charset) throws IOException {
        return readFileToString(Paths.get(filePath), charset);
    }

    /**
     * 读取文件内容为字符串（Path对象）
     * @param path 文件路径对象
     * @param charset 字符编码
     * @return 文件内容
     * @throws IOException 读取异常
     */
    public static String readFileToString(Path path, Charset charset) throws IOException {
        try (Stream<String> lines = Files.lines(path, charset)) {
            return lines.collect(Collectors.joining(System.lineSeparator()));
        }
    }

    /**
     * 读取文件内容为字节数组
     * @param filePath 文件路径
     * @return 文件字节数组
     * @throws IOException 读取异常
     */
    public static byte[] readFileToBytes(String filePath) throws IOException {
        return Files.readAllBytes(Paths.get(filePath));
    }

    /**
     * 按行读取文件内容
     * @param filePath 文件路径
     * @return 文件行列表
     * @throws IOException 读取异常
     */
    public static List<String> readLines(String filePath) throws IOException {
        return readLines(Paths.get(filePath), StandardCharsets.UTF_8);
    }

    /**
     * 按行读取文件内容（指定编码）
     * @param filePath 文件路径
     * @param charset 字符编码
     * @return 文件行列表
     * @throws IOException 读取异常
     */
    public static List<String> readLines(String filePath, Charset charset) throws IOException {
        return readLines(Paths.get(filePath), charset);
    }

    /**
     * 按行读取文件内容（Path对象）
     * @param path 文件路径对象
     * @param charset 字符编码
     * @return 文件行列表
     * @throws IOException 读取异常
     */
    public static List<String> readLines(Path path, Charset charset) throws IOException {
        try (Stream<String> lines = Files.lines(path, charset)) {
            return lines.collect(Collectors.toList());
        }
    }

    /**
     * 写入字符串到文件（UTF-8编码）
     * @param filePath 文件路径
     * @param content 要写入的内容
     * @throws IOException 写入异常
     */
    public static void writeStringToFile(String filePath, String content) throws IOException {
        writeStringToFile(Paths.get(filePath), content, StandardCharsets.UTF_8);
    }

    /**
     * 写入字符串到文件（指定编码）
     * @param filePath 文件路径
     * @param content 要写入的内容
     * @param charset 字符编码
     * @throws IOException 写入异常
     */
    public static void writeStringToFile(String filePath, String content, Charset charset) throws IOException {
        writeStringToFile(Paths.get(filePath), content, charset);
    }

    /**
     * 写入字符串到文件（Path对象）
     * @param path 文件路径对象
     * @param content 要写入的内容
     * @param charset 字符编码
     * @throws IOException 写入异常
     */
    public static void writeStringToFile(Path path, String content, Charset charset) throws IOException {
        Files.write(path, content.getBytes(charset), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
    }

    /**
     * 写入字节数组到文件
     * @param filePath 文件路径
     * @param bytes 要写入的字节数组
     * @throws IOException 写入异常
     */
    public static void writeBytesToFile(String filePath, byte[] bytes) throws IOException {
        Files.write(Paths.get(filePath), bytes, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
    }

    /**
     * 追加字符串到文件（UTF-8编码）
     * @param filePath 文件路径
     * @param content 要追加的内容
     * @throws IOException 写入异常
     */
    public static void appendStringToFile(String filePath, String content) throws IOException {
        appendStringToFile(Paths.get(filePath), content, StandardCharsets.UTF_8);
    }

    /**
     * 追加字符串到文件（指定编码）
     * @param filePath 文件路径
     * @param content 要追加的内容
     * @param charset 字符编码
     * @throws IOException 写入异常
     */
    public static void appendStringToFile(String filePath, String content, Charset charset) throws IOException {
        appendStringToFile(Paths.get(filePath), content, charset);
    }

    /**
     * 追加字符串到文件（Path对象）
     * @param path 文件路径对象
     * @param content 要追加的内容
     * @param charset 字符编码
     * @throws IOException 写入异常
     */
    public static void appendStringToFile(Path path, String content, Charset charset) throws IOException {
        Files.write(path, content.getBytes(charset), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
    }

    // ------------------- 文件操作 -------------------

    /**
     * 复制文件
     * @param source 源文件路径
     * @param target 目标文件路径
     * @throws IOException 复制异常
     */
    public static void copyFile(String source, String target) throws IOException {
        copyFile(Paths.get(source), Paths.get(target));
    }

    /**
     * 复制文件（Path对象）
     * @param source 源文件路径对象
     * @param target 目标文件路径对象
     * @throws IOException 复制异常
     */
    public static void copyFile(Path source, Path target) throws IOException {
        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    }

    /**
     * 移动/重命名文件
     * @param source 源文件路径
     * @param target 目标文件路径
     * @throws IOException 移动异常
     */
    public static void moveFile(String source, String target) throws IOException {
        moveFile(Paths.get(source), Paths.get(target));
    }

    /**
     * 移动/重命名文件（Path对象）
     * @param source 源文件路径对象
     * @param target 目标文件路径对象
     * @throws IOException 移动异常
     */
    public static void moveFile(Path source, Path target) throws IOException {
        Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
    }

    /**
     * 删除文件
     * @param filePath 文件路径
     * @throws IOException 删除异常
     */
    public static void deleteFile(String filePath) throws IOException {
        deleteFile(Paths.get(filePath));
    }

    /**
     * 删除文件（Path对象）
     * @param path 文件路径对象
     * @throws IOException 删除异常
     */
    public static void deleteFile(Path path) throws IOException {
        Files.deleteIfExists(path);
    }

    /**
     * 创建文件（包括必要的父目录）
     * @param filePath 文件路径
     * @throws IOException 创建异常
     */
    public static void createFile(String filePath) throws IOException {
        createFile(Paths.get(filePath));
    }

    /**
     * 创建文件（包括必要的父目录，Path对象）
     * @param path 文件路径对象
     * @throws IOException 创建异常
     */
    public static void createFile(Path path) throws IOException {
        if (!Files.exists(path.getParent())) {
            Files.createDirectories(path.getParent());
        }
        Files.createFile(path);
    }

    // ------------------- 目录操作 -------------------

    /**
     * 创建目录（包括必要的父目录）
     * @param dirPath 目录路径
     * @throws IOException 创建异常
     */
    public static void createDirectory(String dirPath) throws IOException {
        Files.createDirectories(Paths.get(dirPath));
    }

    /**
     * 删除目录（递归删除所有内容）
     * @param dirPath 目录路径
     * @throws IOException 删除异常
     */
    public static void deleteDirectory(String dirPath) throws IOException {
        deleteDirectory(Paths.get(dirPath));
    }

    /**
     * 删除目录（递归删除所有内容，Path对象）
     * @param path 目录路径对象
     * @throws IOException 删除异常
     */
    public static void deleteDirectory(Path path) throws IOException {
        if (Files.exists(path)) {
            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Files.delete(file);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    Files.delete(dir);
                    return FileVisitResult.CONTINUE;
                }
            });
        }
    }

    /**
     * 列出目录下所有文件和子目录
     * @param dirPath 目录路径
     * @return 文件和目录路径列表
     * @throws IOException 读取异常
     */
    public static List<String> listFiles(String dirPath) throws IOException {
        try (Stream<Path> paths = Files.list(Paths.get(dirPath))) {
            return paths.map(Path::toString).collect(Collectors.toList());
        }
    }

    /**
     * 递归列出目录下所有文件和子目录
     * @param dirPath 目录路径
     * @return 所有文件和目录路径列表
     * @throws IOException 读取异常
     */
    public static List<String> listAllFiles(String dirPath) throws IOException {
        try (Stream<Path> paths = Files.walk(Paths.get(dirPath))) {
            return paths.map(Path::toString).collect(Collectors.toList());
        }
    }

    // ------------------- 文件信息 -------------------

    /**
     * 获取文件大小（字节）
     * @param filePath 文件路径
     * @return 文件大小（字节）
     * @throws IOException 读取异常
     */
    public static long getFileSize(String filePath) throws IOException {
        return Files.size(Paths.get(filePath));
    }

    /**
     * 获取文件最后修改时间
     * @param filePath 文件路径
     * @return 最后修改时间（毫秒）
     * @throws IOException 读取异常
     */
    public static long getLastModified(String filePath) throws IOException {
        return Files.getLastModifiedTime(Paths.get(filePath)).toMillis();
    }

    /**
     * 判断文件是否存在
     * @param filePath 文件路径
     * @return 是否存在
     */
    public static boolean exists(String filePath) {
        return Files.exists(Paths.get(filePath));
    }

    /**
     * 判断是否是目录
     * @param filePath 文件路径
     * @return 是否是目录
     */
    public static boolean isDirectory(String filePath) {
        return Files.isDirectory(Paths.get(filePath));
    }

    /**
     * 判断是否是文件
     * @param filePath 文件路径
     * @return 是否是文件
     */
    public static boolean isFile(String filePath) {
        return Files.isRegularFile(Paths.get(filePath));
    }

    // ------------------- 临时文件 -------------------

    /**
     * 创建临时文件
     * @param prefix 文件名前缀
     * @param suffix 文件名后缀
     * @return 临时文件路径
     * @throws IOException 创建异常
     */
    public static String createTempFile(String prefix, String suffix) throws IOException {
        return Files.createTempFile(prefix, suffix).toString();
    }

    /**
     * 创建临时文件（指定目录）
     * @param dirPath 目录路径
     * @param prefix 文件名前缀
     * @param suffix 文件名后缀
     * @return 临时文件路径
     * @throws IOException 创建异常
     */
    public static String createTempFile(String dirPath, String prefix, String suffix) throws IOException {
        return Files.createTempFile(Paths.get(dirPath), prefix, suffix).toString();
    }

    /**
     * 创建临时目录
     * @param prefix 目录名前缀
     * @return 临时目录路径
     * @throws IOException 创建异常
     */
    public static String createTempDirectory(String prefix) throws IOException {
        return Files.createTempDirectory(prefix).toString();
    }

    /**
     * 创建临时目录（指定父目录）
     * @param dirPath 父目录路径
     * @param prefix 目录名前缀
     * @return 临时目录路径
     * @throws IOException 创建异常
     */
    public static String createTempDirectory(String dirPath, String prefix) throws IOException {
        return Files.createTempDirectory(Paths.get(dirPath), prefix).toString();
    }
}